namespace OpenComposite.EII.Repository
{
	using System;
	using System.Collections.Generic;
	using System.ComponentModel.Design;
	using System.Data;
	using System.Drawing;
	using System.Drawing.Design;
	using System.Windows.Forms;
	using System.Workflow.ComponentModel;

	using OpenComposite.EII.Designer.Workflow;
	using OpenComposite.EII.RepositoryUIs;
	using OpenComposite.Workflow;

	using OpenComposite.Base.Collections;
	using OpenComposite.Repository.Properties;
	using OpenComposite.Workflow.Extenders;

	/// <summary>
	/// The Capability Method Item.
	/// </summary>
	[RepositoryItem(ItemType.Verb, "verbs", "verb_id")]
	public class Verb : RepositoryItemBaseEx
	{
		#region Initialization

		/// <summary>
		/// Initializes a new instance of the <see cref="Verb"/> class.
		/// </summary>
		public Verb()
			: base("verb_id", "verb_nm", "verb_desc", "verb_ntext", Resources.sNewVerb)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="Verb"/> class.
		/// </summary>
		/// <param name="bCreateNew">if set to <c>true</c> [b create new].</param>
		public Verb(bool bCreateNew)
			: this()
		{
			if ( bCreateNew )
				this.CreateNew();
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="Verb"/> class.
		/// </summary>
		/// <param name="id">The id.</param>
		public Verb(int id)
			: this()
		{
			this.Load(id);
		}

		#endregion Initialization

		#region Public Members

		#region Properties

		/// <summary>
		/// Gets the allowed child types.
		/// </summary>
		/// <value>The allowed child types.</value>
		public override List<ItemType> AllowedChildTypes
		{
			get { return _LISTALLOWED; }
		}

		/// <summary>
		/// Gets or sets the capability.
		/// </summary>
		/// <value>The capability.</value>
		public ServiceModule Capability
		{
			get
			{
				if ( this.CapabilityID > 0 ) {
					ServiceModule cap = this.RepositoryService.GetItem<ServiceModule>(this.CapabilityID);
					if ( cap == null || cap.IsDeleted || cap.Capability == null ) {
						return null;
					} else {
						return cap;
					}
				} else {
					return null;
				}
			}
			set
			{
				if ( value != null ) {
					this.CapabilityID = value.ID;
				} else {
					this.CapabilityID = -1;
				}
			}
		}

		/// <summary>
		/// Gets or sets the capability ID.
		/// </summary>
		/// <value>The capability ID.</value>
		public int CapabilityID
		{
			get
			{
				int capid = getInt("capability_id", -1);
				if ( capid <= 0 ) {
					DataTable dt = Global.Data.GetRepositoryHierarchyParents(this);
					if ( dt != null && dt.Rows.Count > 0 ) {
						foreach ( DataRow row in dt.Rows ) {
							if ( (ItemType)row["parent_reptype_id"] == ItemType.Capability ||
								(ItemType)row["parent_reptype_id"] == ItemType.Composite ) {
								capid = (int)row["parent_id"];
								break;
							}
						}
					}
				}
				return capid;
			}
			set { setValue("CapabilityID", "capability_id", value); }
		}

		/// <summary>
		/// Gets or sets the default logical method.
		/// </summary>
		/// <value>The default logical method.</value>
		public LogicalWebMethod DefaultLogicalMethod
		{
			get
			{
				LogicalWebMethod lwm = null;
				if ( this.DefaultLogicalMethodID > 0 ) {
					lwm = this.RepositoryService.GetItem<LogicalWebMethod>(this.DefaultLogicalMethodID);
					if ( lwm != null && lwm.IsDeleted )
						lwm = null;
				}
				return lwm;
			}
			set
			{
				this.DefaultLogicalMethodID = ( value == null ? -1 : value.ID );
			}
		}

		/// <summary>
		/// Gets or sets the default logical method ID.
		/// </summary>
		/// <value>The default logical method ID.</value>
		public int DefaultLogicalMethodID
		{
			get { return getInt("log_wmeth_id", -1); }
			set { setValue("DefaultLogicalMethodID", "log_wmeth_id", value); ; }
		}

		/// <summary>
		/// Gets the default name of the logical method.
		/// </summary>
		/// <value>The default name of the logical method.</value>
		public string DefaultLogicalMethodName
		{
			get
			{
				LogicalWebMethod lwm = this.DefaultLogicalMethod;
				if ( lwm == null ) return "";

				return this.DefaultLogicalMethod.Name;
			}
		}

		/// <summary>
		/// Gets the image.
		/// </summary>
		/// <value>The image.</value>
		public override Image Image
		{
			get
			{
				if ( _transparentImage == null ) {
					_transparentImage = Resources.verb;
				}
				return _transparentImage;
			}
		}

		/// <summary>
		/// Gets the image key.
		/// </summary>
		/// <value>The image key.</value>
		public override string ImageKey
		{
			get { return "verb"; }
		}

		/// <summary>
		/// Gets or sets the input business object.
		/// </summary>
		/// <value>The input business object.</value>
		public BusinessObject InputBusinessObject
		{
			get
			{
				BusinessObject bo = null;
				if ( this.InputBusinessObjectID > 0 ) {
					bo = this.RepositoryService.GetItem<BusinessObject>(this.InputBusinessObjectID);
					if ( bo != null && bo.IsDeleted )
						bo = null;
				}
				return bo;
			}
			set { this.InputBusinessObjectID = ( value == null ? -1 : value.ID ); }
		}

		/// <summary>
		/// Gets or sets the input business object ID.
		/// </summary>
		/// <value>The input business object ID.</value>
		public int InputBusinessObjectID
		{
			get { return getInt("verb_input_bobj_id", -1); }
			set
			{
				if ( this.InputBusinessObjectID == value ) return; // EXIT
				BindingListEx<LogicalWebMethod> lstLWM = Global.Data.GetLogicalMethodsOfVerb(this.ID);
				if ( this.DefaultLogicalMethod != null && !lstLWM.Contains(this.DefaultLogicalMethod) ) {
					lstLWM.Add(this.DefaultLogicalMethod);
				}
				if ( lstLWM.Count > 0 ) {
					DialogResult result = MessageBox.Show(
						string.Format("This will change the Input Business Object of all assigned logical methods.{0}{0}Do you really want to continue?", Environment.NewLine),
						"Change Input Business Object", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
					if ( result == DialogResult.No ) return; // EXIT
					setValue("InputBusinessObjectID", "verb_input_bobj_id", value);
					foreach ( var item in lstLWM ) {
						item.SetInputBusinessObjectID(value);
						item.Save();
					}
					return; //EXIT
				}
				setValue("InputBusinessObjectID", "verb_input_bobj_id", value);
			}
		}

		/// <summary>
		/// Gets the name of the input business object.
		/// </summary>
		/// <value>The name of the input business object.</value>
		public string InputBusinessObjectName
		{
			get
			{
				BusinessObject bo = this.InputBusinessObject;
				if ( bo != null )
					return bo.Name;
				else
					return "";
			}
		}

		/// <summary>
		/// Gets or sets the output business object.
		/// </summary>
		/// <value>The output business object.</value>
		public BusinessObject OutputBusinessObject
		{
			get
			{
				BusinessObject bo = null;
				if ( this.OutputBusinessObjectID > 0 ) {
					bo = this.RepositoryService.GetItem<BusinessObject>(this.OutputBusinessObjectID);
					if ( bo != null && bo.IsDeleted )
						bo = null;
				}
				return bo;
			}
			set { this.OutputBusinessObjectID = ( value == null ? -1 : value.ID ); }
		}

		/// <summary>
		/// Gets or sets the output business object ID.
		/// </summary>
		/// <value>The output business object ID.</value>
		public int OutputBusinessObjectID
		{
			get { return getInt("verb_output_bobj_id", -1); }
			set
			{
				if ( this.OutputBusinessObjectID == value ) return; // EXIT
				BindingListEx<LogicalWebMethod> lstLWM = Global.Data.GetLogicalMethodsOfVerb(this.ID);
				if ( this.DefaultLogicalMethod != null && !lstLWM.Contains(this.DefaultLogicalMethod) ) {
					lstLWM.Add(this.DefaultLogicalMethod);
				}
				if ( lstLWM.Count > 0 ) {
					DialogResult result = MessageBox.Show(
						string.Format("This will change the Output Business Object of all assigned logical methods.{0}{0}Do you really want to continue?", Environment.NewLine),
						"Change Output Business Object", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
					if ( result == DialogResult.No ) return; // EXIT
					setValue("OutputBusinessObjectID", "verb_output_bobj_id", value);
					foreach ( var item in lstLWM ) {
						item.SetOutputBusinessObjectID(value);
						item.Save();
					}
					return; // EXIT
				}
				setValue("OutputBusinessObjectID", "verb_output_bobj_id", value);
			}
		}

		/// <summary>
		/// Gets the name of the output business object.
		/// </summary>
		/// <value>The name of the output business object.</value>
		public string OutputBusinessObjectName
		{
			get
			{
				BusinessObject bo = this.OutputBusinessObject;
				if ( bo != null )
					return bo.Name;
				else
					return "";
			}
		}

		/// <summary>
		/// Gets the type of the repository item.
		/// </summary>
		/// <value>The type of the repository item.</value>
		public override ItemType RepositoryItemType
		{
			get { return ItemType.Verb; }
		}

		/// <summary>
		/// Gets the repository item type description.
		/// </summary>
		/// <value>The repository item type description.</value>
		public override string RepositoryItemTypeDescription
		{
			get { return ""; }
		}

		/// <summary>
		/// Gets the name of the repository item type.
		/// </summary>
		/// <value>The name of the repository item type.</value>
		public override string RepositoryItemTypeName
		{
			get { return ItemTypes.GetDisplay(this.RepositoryItemType); }
		}

		/// <summary>
		/// Gets the selected image.
		/// </summary>
		/// <value>The selected image.</value>
		public override Image SelectedImage
		{
			get { return this.Image; }
		}

		/// <summary>
		/// Gets the selected image key.
		/// </summary>
		/// <value>The selected image key.</value>
		public override string SelectedImageKey
		{
			get { return "verb"; }
		}

		/// <summary>
		/// Gets the name of the table.
		/// </summary>
		/// <value>The name of the table.</value>
		public override string TableName
		{
			get { return "verbs"; }
		}

		#endregion Properties

		#region Methods

		/// <summary>
		/// Assigns the logical activity.
		/// </summary>
		/// <param name="idLogicalActivity">The id logical activity.</param>
		/// <returns></returns>
		public LogicalActivity AssignLogicalActivity(int idLogicalActivity)
		{
			RepositoryService repSvc = (RepositoryService)this.GetService(typeof(RepositoryService));
			if ( repSvc == null )
				throw new NullReferenceException("RepositoryService not available.");

			bool bSC;
			LogicalActivity logact = null;
			if ( idLogicalActivity > 0 ) {
				logact = repSvc.GetItem(ItemType.LogicalActivity, idLogicalActivity, true) as LogicalActivity;
				if ( logact.VerbID != this.ID ) {
					setLogActValues(logact);
				}
			} else {
				logact = repSvc.GetItem(ItemType.LogicalActivity, true,
					Global.Status.CurrentRepositoryId, false, false, out bSC) as LogicalActivity;
				setLogActValues(logact);
			}
			return logact;
		}

		/// <summary>
		/// Copies this instance.
		/// </summary>
		/// <param name="deep"><c>true</c> to recursively copy the item and all subitems;
		/// <c>false</c> to copy only the item itself.</param>
		/// <returns>The copied item.</returns>
		public override IRepositoryItem Copy(bool deep)
		{
			return this.CopyInternal(deep, null);
		}
		internal Verb CopyInternal(bool deep, Dictionary<int, int> mapBObjsOldNew)
		{
			Verb copy = new Verb(true);
			copy.InitializeServiceProvider(this);
			this.CopyDataRowToTarget(copy);
			if ( mapBObjsOldNew != null ) {
				if ( copy.InputBusinessObject != null ) {
					if ( mapBObjsOldNew.ContainsKey(copy.InputBusinessObjectID) ) {
						copy.InputBusinessObjectID = mapBObjsOldNew[copy.InputBusinessObjectID];
					} else {
						BusinessObject bo = copy.InputBusinessObject.CopyInternal(deep, mapBObjsOldNew);
						mapBObjsOldNew.Add(copy.InputBusinessObjectID, bo.ID);
						copy.InputBusinessObject = bo;
					}
				}
				if ( copy.OutputBusinessObject != null ) {
					if ( mapBObjsOldNew.ContainsKey(copy.OutputBusinessObjectID) ) {
						copy.OutputBusinessObjectID = mapBObjsOldNew[copy.OutputBusinessObjectID];
					} else {
						BusinessObject bo = copy.OutputBusinessObject.CopyInternal(deep, mapBObjsOldNew);
						mapBObjsOldNew.Add(copy.OutputBusinessObjectID, bo.ID);
						copy.OutputBusinessObject = bo;
					}
				}
			} else {
				if ( copy.InputBusinessObject != null ) {
					copy.InputBusinessObject = copy.InputBusinessObject.Copy(deep) as BusinessObject;
				}
				if ( copy.OutputBusinessObject != null ) {
					copy.OutputBusinessObject = copy.OutputBusinessObject.Copy(deep) as BusinessObject;
				}
			}
			return copy;
		}

		/// <summary>
		/// Gets the icon.
		/// </summary>
		/// <returns></returns>
		public override Icon GetIcon()
		{
			if ( _transparentImage == null ) {
				_transparentImage = Resources.verb;
				_transparentImage.MakeTransparent(Color.Magenta);
			}
			return Icon.FromHandle(_transparentImage.GetHicon());
		}

		/// <summary>
		/// Gets the KPI metrics.
		/// </summary>
		/// <returns></returns>
		public BindingListEx<KPIMetric> GetKPIMetrics()
		{
			return Global.Data.GetRepositoryHierarchyChildRepositoryList<KPIMetric>(
					this.RepositoryItemType, this.ID, ItemType.KPI_Metric);
		}

		/// <summary>
		/// Sets the drag drop data object.
		/// </summary>
		/// <param name="dataObj">The data object.</param>
		public override void SetDragDropDataObject(IDataObject dataObj)
		{
			base.SetDragDropDataObject(dataObj);

			ToolboxItem ti = null;
			//if ( this.DefaultLogicalMethod != null &&
			//     this.DefaultLogicalMethod.IsAssignedTo == LogicalMethodAssignedTo.MessageQueue &&
			//     this.DefaultLogicalMethod.MessageQueue != null ) {
			//    if ( this.DefaultLogicalMethod.ExtendedProperties.MessageQueueSend ) {
			//        ti = OpenComposite.EII.Designer.Workflow.ToolboxService.GetToolboxItem(
			//            typeof(OpenComposite.Workflow.LogicalAsyncStartActivity));
			//    } else {
			//        ti = OpenComposite.EII.Designer.Workflow.ToolboxService.GetToolboxItem(
			//            typeof(OpenComposite.Workflow.LogicalAsyncEndActivity));
			//    }
			//} else {
			ti = OpenComposite.EII.Designer.Workflow.ToolboxService.GetToolboxItem(
									typeof(OpenComposite.Workflow.LogicalCapabilityActivity));
			//}
			OpenComposite.Workflow.LogicalCapabilityActivityToolboxItem ati = ti as OpenComposite.Workflow.LogicalCapabilityActivityToolboxItem;

			if ( ati != null ) {
				ati.InitializeLogicalCapabilityActivity += new EventHandler<OpenComposite.Workflow.InitializeLogicalCapabilityActivityEventArgs>(ati_InitializeLogicalCapabilityActivity);
			}
			dataObj.SetData(typeof(ToolboxItem), ti);
		}

		/// <summary>
		/// Shows the new item form.
		/// </summary>
		/// <param name="idRepository">The repository ID.</param>
		/// <param name="bAllowContinue">if set to <c>true</c> to allow save and continue.</param>
		/// <param name="parentItem">The parent item.</param>
		/// <param name="idDomain">The domain ID.</param>
		/// <param name="parentItemNew">The new parent item.</param>
		/// <returns></returns>
		public override DialogResult ShowNewItemForm(int idRepository, bool bAllowContinue,
			IRepositoryItem parentItem, ref int idDomain, out IRepositoryItem parentItemNew)
		{
			FormCreateNewVerb dlg = new FormCreateNewVerb(this, bAllowContinue);
			dlg.DomainID = idDomain;
			dlg.ShowAllFolders = false;
			dlg.ParentItem = parentItem;
			DialogResult result = dlg.ShowDialog();
			if ( result == DialogResult.OK || result == DialogResult.Retry ) {
				idDomain = dlg.DomainID;
				parentItemNew = dlg.NewParentItem;
				if ( parentItemNew is Capability ) {
					this.CapabilityID = parentItem.ID;
				}
			} else {
				idDomain = 0;
				parentItemNew = null;
			}
			return result;
		}

		#endregion Methods

		#endregion Public Members

		#region Internal Members

		#region Methods

		/// <summary>
		/// Sets the input business object ID.
		/// </summary>
		/// <param name="value">The value.</param>
		internal void SetInputBusinessObjectID(int value)
		{
			if ( this.InputBusinessObjectID == value ) return; // EXIT
			BindingListEx<LogicalWebMethod> lstLWM = Global.Data.GetLogicalMethodsOfVerb(this.ID);
			if ( this.DefaultLogicalMethod != null && !lstLWM.Contains(this.DefaultLogicalMethod) ) {
				lstLWM.Add(this.DefaultLogicalMethod);
			}
			setValue("InputBusinessObjectID", "verb_input_bobj_id", value);
			if ( lstLWM.Count > 0 ) {
				foreach ( var item in lstLWM ) {
					item.SetInputBusinessObjectID(value);
					item.Save();
				}
			}
		}

		/// <summary>
		/// Sets the output business object ID.
		/// </summary>
		/// <param name="value">The value.</param>
		internal void SetOutputBusinessObjectID(int value)
		{
			if ( this.OutputBusinessObjectID == value ) return; // EXIT
			BindingListEx<LogicalWebMethod> lstLWM =
				Global.Data.GetLogicalMethodsOfVerb(this.ID);
			if ( this.DefaultLogicalMethod != null && !lstLWM.Contains(this.DefaultLogicalMethod) ) {
				lstLWM.Add(this.DefaultLogicalMethod);
			}
			setValue("OutputBusinessObjectID", "verb_output_bobj_id", value);
			if ( lstLWM.Count > 0 ) {
				foreach ( var item in lstLWM ) {
					item.SetOutputBusinessObjectID(value);
					item.Save();
				}
			}
		}

		#endregion Methods

		#endregion Internal Members

		#region Private Members

		#region Static Fields

		private static List<ItemType> _LISTALLOWED = new List<ItemType>();

		#endregion Static Fields

		#region Fields

		private Bitmap _transparentImage = null;

		#endregion Fields

		#region Event Handlers

		//protected override void OnItemChanged(System.Reflection.MemberInfo member, object oldValue, object newValue)
		//{
		//	base.OnItemChanged(member, oldValue, newValue);
		//	//if ( !( newValue is int ) && newValue != null ) return;
		//	//if ( member.Name == "InputBusinessObjectID" ) {
		//	//    LogicalWebMethod lwm = this.DefaultLogicalMethod;
		//	//    if ( lwm != null ) {
		//	//        lwm.InputBusinessObjectID = newValue == null ? -1 : (int)newValue;
		//	//        lwm.Save();
		//	//    }
		//	//} else if ( member.Name == "OutputBusinessObjectID" ) {
		//	//    LogicalWebMethod lwm = this.DefaultLogicalMethod;
		//	//    if ( lwm != null ) {
		//	//        lwm.OutputBusinessObjectID = newValue == null ? -1 : (int)newValue;
		//	//        lwm.Save();
		//	//    }
		//	//}
		//}
		private void ati_InitializeLogicalCapabilityActivity(object sender, OpenComposite.Workflow.InitializeLogicalCapabilityActivityEventArgs e)
		{
			OpenComposite.Workflow.LogicalCapabilityActivityToolboxItem ati = sender as OpenComposite.Workflow.LogicalCapabilityActivityToolboxItem;
			if ( e.LogicalCapabilityActivity != null ) {
				LogicalActivity logact;
				if ( e.LogicalCapabilityActivity.LogicalActivityId == 0 && ati.Tag is int )
					logact = this.AssignLogicalActivity((int)ati.Tag);
				else
					logact = this.AssignLogicalActivity(e.LogicalCapabilityActivity.LogicalActivityId);

				e.LogicalCapabilityActivity.LogicalActivityId = logact.ID;
				e.LogicalCapabilityActivity.LogicalActivityName = logact.Name;
				e.LogicalCapabilityActivity.Capability = this.Name;
				e.LogicalCapabilityActivity.HasOutputObject = ( this.OutputBusinessObject != null );
				if ( this.OutputBusinessObject != null ) {
					e.LogicalCapabilityActivity.SetValue(OutputVariableNameExtenderProvider.OutputVarNameProperty,
						string.Format("{0}_{1}", this.Name, this.OutputBusinessObject.Name));
				}

				logact.LogicalMethodID = this.DefaultLogicalMethodID;
				logact.LogicalActivityType = LogicalActivityType.LogicalCapability;

				RepositorySurfaceManager surfaceManager = Global.Data.RepositoryService.GetService<RepositorySurfaceManager>();
				if ( surfaceManager != null && surfaceManager.ActiveDesignSurface != null ) {
					IDesignerHost host = surfaceManager.ActiveDesignSurface.ComponentContainer as IDesignerHost;
					RepositorySurface repSurface = surfaceManager.ActiveDesignSurface as RepositorySurface;
					if ( repSurface.Controller.RepositoryItem.RepositoryItemType == ItemType.Workflow ) {
						logact.WorkflowID = repSurface.Controller.RepositoryItem.ID;
						logact.Save();
					}
					if ( host != null ) {

						// TODO: set workflow id of logact here
						CompositeActivity ca = host.RootComponent as CompositeActivity;
						//WorkflowController wfCtrl = surfaceManager.ActiveDesignSurface.
						if ( ca != null ) {
							e.LogicalCapabilityActivity.Name =
								WorkflowHelpers.EnsureUniqueName(ca, this.Name);
							e.LogicalCapabilityActivity.Text =
								WorkflowHelpers.MakeNameWithSpaces(this.Name);
						}

					}
				} else {
				}
				if ( ati != null ) {
					ati.Tag = logact.ID;
				}
			}
		}

		#endregion Event Handlers

		#region Methods

		private void setLogActValues(LogicalActivity logact)
		{
			logact.BeginEdit();
			try {
				logact.VerbID = this.ID;
				logact.LogicalActivityType = LogicalActivityType.LogicalCapability;
				logact.Name = this.Name;
				logact.Description = this.Description;
				logact.NText = this.NText;
			} finally {
				logact.EndEdit(true);
			}
		}

		#endregion Methods

		#endregion Private Members
	}
}